/*****************************************************************************
  Copyright ?2002-2004 by Martin Cook. All rights are reserved. If you like
  this code then feel free to go ahead and use it. The only thing I ask is 
  that you don't remove or alter my copyright notice. Your use of this 
  software is entirely at your own risk. I make no claims about the 
  reliability or fitness of this code for any particular purpose. If you 
  make changes or additions to this code then please clearly mark your code 
  as yours. If you have questions or comments then please contact me at: 
  martin@codegator.com
  
  Have Fun! :o)
*****************************************************************************/

using System;
using System.Configuration;
using System.Xml;

namespace CG.Security.Data.Configuration
{

	/// <summary>
	/// Handler for the CG.Security.Data/runtimeSetup configuration section.
	/// </summary>
	internal sealed class DataSettingsHandler : IConfigurationSectionHandler
	{

		// ******************************************************************
		// IConfigurationSectionHandler implementation.
		// ******************************************************************

		#region IConfigurationSectionHandler implementation

		/// <summary>
		/// Called by the framework whenever anything tries to read a 
		/// CG.Security.Data/runtimeSetup configuration section.
		/// </summary>
		/// <param name="parent">The configuration settings in a corresponding 
		/// parent configuration section.</param>
		/// <param name="configContext">An HttpConfigurationContext when Create 
		/// is called from the ASP.NET configuration system. Otherwise, this 
		/// parameter is reserved and is a null reference.</param>
		/// <param name="section">The XmlNode that contains the configuration 
		/// information from the configuration file. Provides direct access to 
		/// the XML contents of the configuration section.</param>
		/// <returns>A configuration object.</returns>
		public object Create(
			object parent,
			object configContext,
			XmlNode section
			)
		{

			// Read the defaultSection attribute.
			string defaultSection = _ReadDefaultSection(section);

			// Read the correct installedAssembly entry.
			XmlNode assemblySection = _ReadInstalledAssembly(
				defaultSection, 
				section
				);

			// Read the value of the sectionName attribute.
			string sectionNameValue = _ReadAttributeValue(
				"sectionName",
				assemblySection
				);

			// Read the value of the targetAssembly attribute.
			string targetAssemblyValue = _ReadAttributeValue(
				"targetAssembly",
				assemblySection
				);

			// Read the value of the targetNamespace attribute.
			string targetNamespaceValue = _ReadAttributeValue(
				"targetNamespace",
				assemblySection
				);

			// Read the value of the connectionString attribute.
			string connectionStringValue = _ReadAttributeValue(
				"connectionString",
				assemblySection
				);

			// Create an object to contain the runtime setup.
			return new DataSettings(
				sectionNameValue,
				targetAssemblyValue,
				targetNamespaceValue,
				connectionStringValue
				);

		} // End Create()
        
		#endregion

		// ******************************************************************
		// Private methods.
		// ******************************************************************

		#region Private methods

		/// <summary>
		/// Reads the defaultSection attribute.
		/// </summary>
		/// <param name="section">The XmlNode that contains the configuration 
		/// information from the configuration file. Provides direct access to 
		/// the XML contents of the configuration section.</param>
		/// <returns>The value of the defaultAssembly attribute.</returns>
		private string _ReadDefaultSection(
			XmlNode section
			)
		{

			// Read the defaultSection attribute.
			XmlNode node = section.Attributes["defaultSection"];

			// Sanity check the results before using them.
			if (node == null)
				throw new ConfigurationException(
					"Missing defaultSection attribute!"
					);

			// Return the value of the attribute.
			return node.Value;

		} // End _ReadDefaultSection()

		// ******************************************************************

		/// <summary>
		/// Reads a named assembly section.
		/// </summary>
		/// <param name="name">The name of an installedAssembly entry.</param>
		/// <param name="section">The XmlNode that contains the configuration 
		/// information from the configuration file. Provides direct access to 
		/// the XML contents of the configuration section.</param>
		/// <returns>The installedAssembly XmlNode.</returns>
		private System.Xml.XmlNode _ReadInstalledAssembly(
			string name, 
			XmlNode section
			)
		{

			// Locate the appropriate assembly section.
			XmlNode node = section.SelectSingleNode(
				"installedAssembly/add[@sectionName='" + name + "']"
				);

			// Sanity check the results before using them.
			if (node == null)
				throw new ConfigurationException(
					"Unable to locate the installedAssembly " + name + "!"
					);

			// Return the node.
			return node;
            
		} // End _ReadInstalledAssembly()

		// ******************************************************************

		/// <summary>
		/// Reads the value of an attribute from an installedAssembly.
		/// </summary>
		/// <param name="name">The name of an attribute for an 
		/// installedAssembly section.</param>
		/// <param name="assemblySection">The XmlNode that contains the 
		/// configuration information from the configuration file. Provides 
		/// direct access to the XML contents of the configuration section.
		/// </param>
		/// <returns></returns>
		private string _ReadAttributeValue(
			string name,
			XmlNode assemblySection
			)
		{

			// Locate the attribute.
			XmlNode node = assemblySection.Attributes[name];

			// Sanity check the results before using them.
			if (node == null)
				throw new ConfigurationException(
					"Unable to locate the " + name + " attribute!"
					);

			// Return the value of the attribute.
			return node.Value;

		} // End _ReadAttributeValue()

		#endregion

	} // End class DataSettingsHandler

} // End namespace CG.Security.Data.Configuration

